/*
 * Copyright 2011 Jin Kwon <jinahya at gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.googlecode.flac4j.format.metadata;


import com.googlecode.jinahya.io.BitInput;
import com.googlecode.jinahya.io.BitOutput;
import com.googlecode.jinahya.util.BitAccessible;

import java.io.IOException;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;


/**
 *
 * @author Jin Kwon <jinahya at gmail.com>
 * @see <a href="http://goo.gl/moEDP">flac format</a>
 */
@XmlType(propOrder = {"lastBlock", "blockType", "dataLength"})
public class Header implements BitAccessible {


    public static Header newInstance(final BlockType blockType) {

        final Header instance = new Header();
        instance.setBlockType(blockType);

        return instance;
    }


    @Override
    public void read(final BitInput input) throws IOException {

        lastBlock = input.readBoolean();
        blockType = BlockType.valueOf(input.readUnsignedInt(7));
        dataLength = input.readUnsignedInt(24);
    }


    @Override
    public void write(final BitOutput output) throws IOException {

        output.writeBoolean(lastBlock);
        output.writeUnsignedInt(7, blockType.getValue());
        output.writeUnsignedINTEGER(24, dataLength);
    }


    /**
     * Returns parent block.
     *
     * @return parent block.
     */
    public Block getBlock() {
        return block;
    }


    /**
     * Sets parent block.
     *
     * @param block parent block.
     */
    public void setBlock(final Block block) {

        if (block == null) {
            throw new NullPointerException("null block");
        }

        this.block = block;
    }


    /**
     * Returns last block flag.
     *
     * @return last block flag
     */
    public boolean isLastBlock() {
        return lastBlock;
    }


    /**
     * Sets last block flag.
     * 
     * @param lastBlock last block flag.
     */
    public void setLastBlock(final boolean lastBlock) {
        this.lastBlock = lastBlock;
    }


    // --------------------------------------------------------------- blockType
    /**
     * Returns block type.
     *
     * @return block type.
     */
    public BlockType getBlockType() {
        return blockType;
    }


    /**
     * Sets block type.
     *
     * @param blockType block type.
     */
    public void setBlockType(final BlockType blockType) {

        if (blockType == null) {
            throw new NullPointerException("null blockType");
        }

        this.blockType = blockType;
    }


    @XmlAttribute(name = "blockType")
    public String getBlockTypeName() {

        if (blockType == null) {
            return null;
        }

        return getBlockType().name();
    }


    public void setBlockTypeName(final String blockTypeName) {

        if (blockTypeName == null) {
            throw new NullPointerException("null blockTypeName");
        }

        setBlockType(BlockType.valueOf(blockTypeName));
    }


    // -------------------------------------------------------------- dataLength
    /**
     * Returns data length (in bytes).
     *
     * @return data length
     */
    public int getDataLength() {
        return dataLength;
    }


    /**
     * Sets data length (in bytes).
     *
     * @param dataLength data length
     */
    public void setDataLength(final int dataLength) {

        if (dataLength >> 24 != 0) {
            throw new IllegalArgumentException(
                "dataLength(" + dataLength + ") >> 24 != 0");
        }

        this.dataLength = dataLength;
    }


    @XmlTransient
    private Block block;


    /** last. */
    @XmlElement(required = true)
    private boolean lastBlock;


    /** type. */
    @XmlElement(required = true)
    private BlockType blockType;


    /** length. */
    @XmlElement(required = true)
    private int dataLength;


}

